import { RequestEnum } from "./enum"
import axios from "axios"
import _ from "lodash"

export class VAxios {
  axiosInstance = null

  options = null

  constructor(options) {
    this.options = options

    this.createAxios()
    this.setupInterceptors()
  }

  createAxios() {
    this.axiosInstance = axios.create(this.options)
  }

  getTransform() {
    const { transform } = this.options
    return transform
  }

  getAxios() {
    return this.axiosInstance
  }

  configAxios(config) {
    const axiosInstance = this.getAxios()

    if (!axiosInstance) return

    this.createAxios(config)
  }

  setHeader(headers) {
    const axiosInstance = this.getAxios()

    if (!axiosInstance) return

    Object.assign(axiosInstance.defaults.headers, headers)
  }

  setupInterceptors() {
    const transform = this.getTransform()
    const axiosInstance = this.getAxios()

    if (!transform) return

    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform

    // 请求拦截器
    axiosInstance.interceptors.request.use(
      (config) => {
        return requestInterceptors(config, config.requestOptions)
      },
      (error) => {
        return requestInterceptorsCatch && requestInterceptorsCatch(error)
      }
    )

    // 响应拦截器
    axiosInstance.interceptors.response.use(
      (response) => {
        return responseInterceptors(response, response.config.requestOptions)
      },
      (error) => {
        return responseInterceptorsCatch(error)
      }
    )
  }

  get(url, parameters, options) {
    return this.request({ url, params: parameters, method: RequestEnum.GET }, options)
  }

  post(url, parameters, options) {
    return this.request(
      { url, data: parameters, method: RequestEnum.POST },
      options
    )
  }

  async request(config, options) {
    const axiosInstance = this.getAxios()

    let config_ = _.cloneDeep(config)

    // 获取钩子
    const { beforeRequestHook, beforeResHook } = this.getTransform()

    const { requestOptions } = this.options

    // 合并配置项
    const opt = Object.assign({}, requestOptions, options)

    if (beforeRequestHook && _.isFunction(beforeRequestHook)) {
      config_ = beforeRequestHook(config_, opt)
    }

    config_.requestOptions = opt

    if (beforeResHook && _.isFunction(beforeResHook)) {
      return beforeResHook(config_, () => axiosInstance.request(config_))
    }
  }
}
